package com.edev.support.ddd;

import com.edev.support.ddd.utils.EntityBuilder;
import com.edev.support.ddd.utils.EntityUtils;
import com.edev.support.entity.Entity;
import com.edev.support.subclass.utils.SubClassUtils;
import com.edev.support.utils.BeanUtils;
import com.edev.support.utils.DowncastHelper;
import com.edev.support.utils.NameUtils;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 领域驱动设计的通用工厂类（DDD核心工厂）
 * <p>
 * 核心职责：
 * 1. 领域实体对象创建（支持普通实体和子类实体）
 * 2. 从JSON/数据库到领域对象的转换
 * 3. 类型检查与类型安全转换
 * <p>
 * 主要功能：
 * - 自动处理实体继承关系
 * - 支持嵌套实体创建
 * - 字段类型自动转换
 */
@Component
public class DddFactory {
    @Autowired
    private DowncastHelper downcastHelper;

    /**
     * 检查某个类是否为领域实体
     * @param clazz 待检查的类对象
     * @return true-是领域实体类，false-非领域实体类
     */
    public boolean isEntity(Class<?> clazz) {
        return EntityUtils.isEntity(clazz);
    }

    /**
     * 通过类名获取领域实体类（带泛型类型检查）
     * @param className 全限定类名
     * @param <E> 实体类型（继承自Entity）
     * @param <S> 序列化主键类型
     * @return 实体类的Class对象
     * @throws ClassCastException 当该类不是Entity的子类时抛出
     */
    @SuppressWarnings("unchecked")
    public <E extends Entity<S>,S extends Serializable> Class<E> 
        getClazz(String className) {
        return (Class<E>) BeanUtils.getClazz(className);
    }

    /**
     * 通过JSON获取数据并创建领域实体。
     * 如果有继承关系，则根据JSON中的数据自动选择子类。
     * <p>
     * 使用示例：
     * <pre>
     * Map<String,Object> json = new HashMap<>();
     * json.put("id", 1001L);
     * json.put("name", "测试订单");
     * Order order = dddFactory.createEntityByJson("com.example.Order", json);
     * </pre>
     * @param className 目标实体类的全限定类名
     * @param json 以JSON形式输入的数据
     * @return 实例化的领域实体（携带数据）
     */
    public <E extends Entity<S>,S extends Serializable> 
        E createEntityByJson(@NonNull String className, Map<String, Object> json) {
        if(json==null) return null;
        Class<E> clazz = getClazz(className);
        return createEntityByJson(clazz, json);
    }

    /**
     * 通过JSON获取数据并创建领域实体。
     * 如果有继承关系，则根据JSON中的数据自动选择子类。
     * <p>
     * 使用示例：
     * <pre>
     * Map<String,Object> json = new HashMap<>();
     * json.put("id", 1001L);
     * json.put("name", "测试订单");
     * Order order = dddFactory.createEntityByJson(Order.class, json);
     * </pre>
     * @param clazz 目标实体类
     * @param json 以JSON形式输入的数据
     * @return 实例化的领域实体（携带数据）
     */
    public <E extends Entity<S>,S extends Serializable> 
        E createEntityByJson(@NonNull Class<E> clazz, Map<String, Object> json) {
        if(json==null) return null;
        if(EntityUtils.hasSubClass(clazz)) {//create subclass entity
            Class<E> subclass = SubClassUtils.getSubClassByJson(clazz, json);
            return createSimpleEntityByJson(subclass, json);
        } else //create normal entity
            return createSimpleEntityByJson(clazz, json);
    }

    /**
     * 通过JSON获取数据并创建领域实体（不处理继承关系）。
     * <p>
     * 处理逻辑：
     * 1. 遍历该实体的所有字段
     * 2. 递归嵌套的处理实体字段及实体字段里的字段
     * 3. 如果是实体对象则自动转换为实体对象
     * 4. 如果是集合对象则自动转换为集合对象
     * 5. 如果是基本类型则自动转换为基本类型
     * @param clazz 目标实体类
     * @param json 以JSON形式输入的数据
     * @return 实例化的领域实体（携带数据）
     */
    @SuppressWarnings("unchecked")
    public <E extends Entity<S>,S extends Serializable> 
        E createSimpleEntityByJson(@NonNull Class<E> clazz, @NonNull Map<String, Object> json) {
        E entity = EntityBuilder.build(clazz);
        Field[] fields = entity.findAllFields();
        for(Field field : fields) {
            String fieldName = field.getName();
            Type type = entity.getTypeByMethod(fieldName);
            Object value = json.get(fieldName);
            if(type==null) continue;
            if((type instanceof Class)&&isEntity((Class<?>) type))
                value = createEntityByJson((Class<E>) type, (Map<String, Object>) value);
            else if(isListOrSetOfEntities(type))
                value = createEntityByJsonForList(type, value);
            else
                value = downcastHelper.downcast(type, value);
            entity.setValueByMethod(fieldName, value);
        }
        return entity;
    }

    /**
     * 判断类型是否为实体集合（List/Set）
     * <p>
     * 典型应用场景：
     * - 处理一对多与多对多的关联关系
     * - 解析嵌套的实体集合字段
     * @param type 待检查类型
     * @return true-是实体集合类型
     */
    public boolean isListOrSetOfEntities(Type type) {
        if(type instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType)type;
            Class<?> clazz = (Class<?>)pt.getRawType();
            Type ata = pt.getActualTypeArguments()[0];
            return (clazz.equals(List.class) || clazz.equals(Set.class)) &&
                    ((ata instanceof Class)&&isEntity((Class<?>) ata));
        }
        return false;
    }

    /**
     * 通过JSON数组中获取数据并创建实体集合（批量JSON反序列化）
     * <p>
     * JSON数组的示例输入：
     * [
     *   {"id":1, "name":"实体1"},
     *   {"id":2, "name":"实体2"}
     * ]
     * @param type 集合泛型类型
     * @param value JSON数组数据
     * @return 实体对象列表
     */
    @SuppressWarnings("unchecked")
    public <E extends Entity<S>, S extends Serializable> 
        List<E> createEntityByJsonForList(@NonNull Type type, Object value) {
        if (!(type instanceof ParameterizedType)) return new ArrayList<>();
        if (!(value instanceof Collection)) return new ArrayList<>();
        ParameterizedType pt = (ParameterizedType) type;
        Collection<Map<String,Object>> collection = (Collection<Map<String,Object>>) value;
        Type ata = pt.getActualTypeArguments()[0];
        Class<E> ataClass = (Class<E>) ata;
        List<E> list = new ArrayList<>();
        collection.forEach(json->list.add(createEntityByJson(ataClass, json)));
        return list;
    }

    /**
     * 从数据库查询一条数据并创建实体对象。
     * 如果有继承关系，则根据数据库中的数据自动选择子类。
     * <p>
     * 使用示例：
     * Map<String,Object> row = new HashMap<>();
     * row.put("id", 1001L);
     * row.put("name", "测试订单");
     * Order order = dddFactory.createEntityByRow("com.example.Order", row);
     * @param className 目标实体类的全限定类名
     * @param row 数据库行数据
     * @return 实例化的领域实体（携带数据）
     */
    public <E extends Entity<S>, S extends Serializable> 
        E createEntityByRow(@NonNull String className, Map<String, Object> row) {
        Class<E> clazz = getClazz(className);
        return createEntityByRow(clazz, row);
    }

    /**
     * 从数据库查询一条数据并创建实体对象。
     * 如果有继承关系，则根据数据库中的数据自动选择子类。
     * <p>
     * 使用示例：
     * Map<String,Object> row = new HashMap<>();
     * row.put("id", 1001L);
     * row.put("name", "测试订单");
     * Order order = dddFactory.createEntityByRow(Order.class, row);
     * @param clazz 目标实体类
     * @param row 数据库行数据
     * @return 实例化的领域实体（携带数据）
     */
    public <E extends Entity<S>, S extends Serializable> 
        E createEntityByRow(@NonNull Class<E> clazz, Map<String, Object> row) {
        if(row==null|| row.isEmpty()) return null;
        if(EntityUtils.hasSubClass(clazz) && SubClassUtils.isParent(clazz)) {
            Class<E> subclass = SubClassUtils.getSubClassByRow(clazz, row);
            return createSimpleEntityByRow(subclass, row);
        }
        return createSimpleEntityByRow(clazz, row);
    }

    /**
     * 从数据库查询一条数据并创建实体对象（不处理继承关系）。
     * <p>
     * 处理逻辑：
     * 1. 遍历该实体的所有字段
     * 2. 从数据库行数据中获取对应字段的值
     * 3. 自动转换为实体字段对应的类型
     * 4. 设置实体字段的值
     * @param clazz 目标实体类
     * @param row 数据库行数据
     * @return 实例化的领域实体（携带数据）
     */
    public <E extends Entity<S>, S extends Serializable> 
        E createSimpleEntityByRow(@NonNull Class<E> clazz, @NonNull Map<String, Object> row) {
        E entity = EntityBuilder.build(clazz);
        for(Map.Entry<String, Object> entry: row.entrySet()) {
            String column = entry.getKey();
            Object value = entry.getValue();
            String fieldName = NameUtils.convertToCamelCase(column);
            Type type = entity.getType(fieldName);
            if (type==null) continue;
            value = downcastHelper.downcast(type, value);
            entity.setValue(fieldName, value);
        }
        return entity;
    }

    /**
     * 从数据库查询多条数据并创建实体集合（批量数据库查询结果反序列化）。
     * @param className 目标实体类的全限定类名
     * @param list 数据库行数据集合
     * @return 实体对象列表
     */
    public <E extends Entity<S>, S extends Serializable> List<E> createEntityByRowForList(@NonNull String className, Collection<Map<String, Object>> list) {
        Class<E> clazz = getClazz(className);
        return createEntityByRowForList(clazz, list);
    }

    /**
     * 从数据库查询多条数据并创建实体集合（批量数据库查询结果反序列化）。
     * @param clazz 目标实体类
     * @param list 数据库行数据集合
     * @return 实体对象列表
     */
    public <E extends Entity<S>, S extends Serializable> List<E> createEntityByRowForList(@NonNull Class<E> clazz, Collection<Map<String, Object>> list) {
        if(list==null||list.isEmpty()) return new ArrayList<>();
        List<E> entities = new ArrayList<>();
        list.forEach(row->entities.add(createEntityByRow(clazz,row)));
        return entities;
    }
}
